﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Twodi.Aspect;
using Twodi.Interfaces;
using Twodi.Input;

namespace Twodi.Behavior
{
    /// <summary>
    /// Aspecto responsavel por definir como o componente se comporta.
    /// </summary>
    /// <typeparam name="T">Tipo do componente.</typeparam>
    public abstract class AbstractBehavior<T> : DependentAspect<T>, IUpdateable, IDrawable, IGameComponent, IKeyboardHandler, IMouseHandler
    {
        /// <summary>
        /// Ordem de update do comportamento.
        /// </summary>
        private int updateOrder = 0;

        /// <summary>
        /// Ordem de draw do comportamento.
        /// </summary>
        private int drawOrder = 0;

        /// <summary>
        /// Informa se comportamento esta ativo.
        /// </summary>
        private bool enabled = true;

        /// <summary>
        /// Informa se comportamento esta visivel.
        /// </summary>
        private bool visible = true;

        /// <summary>
        /// Construtor padrão.
        /// </summary>
        /// <param name="component">Componente a ser manipulado pelo comportamento.</param>
        public AbstractBehavior(T component)
            : base(component)
        {

        }

        /// <summary>
        /// Inicializa o comportamento.
        /// </summary>
        public virtual void Initialize()
        {

        }

        /// <summary>
        /// Responsavel por atualizar o comportamento.
        /// </summary>
        /// <param name="gameTime">Tempo do jogo.</param>
        public virtual void Update(GameTime gameTime)
        {

        }

        /// <summary>
        /// Responsavel por renderizar o comportamento.
        /// </summary>
        /// <param name="gameTime">Tempo do jogo.</param>
        public virtual void Draw(GameTime gameTime)
        {

        }

        /// <summary>
        /// Responsavel por manipular input teclado do comportamento.
        /// </summary>
        /// <param name="input">Input local.</param>
        /// <returns>True se deve continuar a manipular proximos componentes. False se deve ser cancelado.</returns>
        public virtual bool Handle(KeyboardInput input)
        {
            return true;
        }

        /// <summary>
        /// Responsavel por manipular input de mouse do comportamento.
        /// </summary>
        /// <param name="input">Input local.</param>
        /// <returns>True se deve continuar a manipular proximos componentes. False se deve ser cancelado.</returns>
        public virtual bool Handle(MouseInput input)
        {
            return true;
        }

        /// <summary>
        /// Informa se comportamento esta ativo.
        /// </summary>
        public bool Enabled
        {
            get
            {
                return this.enabled;
            }
            set
            {
                this.enabled = value;
                onEnabledChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// Informa se comportamento esta visivel.
        /// </summary>
        public bool Visible
        {
            get
            {
                return this.visible;
            }
            set
            {
                this.visible = value;
                onVisibleChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// Ordem de update do comportamento.
        /// </summary>
        public int UpdateOrder
        {
            get
            {
                return this.updateOrder;
            }
            set
            {
                this.updateOrder = value;
                onUpdateOrderChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// Ordem de draw do comportamento.
        /// </summary>
        public int DrawOrder
        {
            get
            {
                return this.drawOrder;
            }
            set
            {
                this.drawOrder = value;
                onDrawOrderChanged(EventArgs.Empty);
            }
        }

        /// <summary>
        /// Evento invocado quando enabled é alterado.
        /// </summary>
        public event EventHandler<EventArgs> EnabledChanged;

        /// <summary>
        /// Evento invocado quando update order é alterado.
        /// </summary>
        public event EventHandler<EventArgs> UpdateOrderChanged;

        /// <summary>
        /// Evento invocado quando draw order é alterado.
        /// </summary>
        public event EventHandler<EventArgs> DrawOrderChanged;

        /// <summary>
        /// Evento invocado quando visible é alterado.
        /// </summary>
        public event EventHandler<EventArgs> VisibleChanged;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        private void onEnabledChanged(EventArgs e)
        {
            if (EnabledChanged != null)
            {
                EnabledChanged(this, e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        private void onUpdateOrderChanged(EventArgs e)
        {
            if (UpdateOrderChanged != null)
            {
                UpdateOrderChanged(this, e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eventArgs"></param>
        protected void onDrawOrderChanged(EventArgs e)
        {
            if (DrawOrderChanged != null)
            {
                UpdateOrderChanged(this, e);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected void onVisibleChanged(EventArgs e)
        {
            if (VisibleChanged != null)
            {
                UpdateOrderChanged(this, e);
            }
        }
    }
}
